#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include <map>

#define COMMAND_SIZE 100
#define FORMAT "[%s@%s %s]# "
#define ARGV_SIZE 12
#define SLASH '/'

extern char** environ;
char* none ="/None";
// last exit code
int lastcode = 0;

void PrintCommandPrompt(std::map<std::string,std::string>& env)
{
	char command[COMMAND_SIZE];
	//const char* user = getenv("USER");
	////printf("%s\n",user);
	//if (user==nullptr)
	//	user =none;
	//const char* hostname = getenv("HOSTNAME");
	////printf("%s\n",hostname);
	//if (hostname==nullptr)
	//	hostname =none;
	//char* pwd = getenv("PWD");
	////printf("%s\n",pwd);
	//if (pwd==nullptr)
        //        pwd =none;
	const char* user =(char*)env["USER"].c_str(); 
	const char* hostname =(char*)env["HOSTNAME"].c_str(); 
	char* pwd =(char*)env["PWD"].c_str(); 
	int len = strlen(pwd);
	char* mypwd=NULL;
	for (int i=len;i>0;i--)
	{
		if(pwd[i]==SLASH)
		{
			mypwd=pwd+i;
			break;
		}
	}
	if (mypwd==NULL)
		mypwd=pwd;
	snprintf(command, sizeof(command), FORMAT, user, hostname, mypwd);
	printf("%s",command);
	fflush(stdout);
}

void GetCommand(std::vector<std::string>& commend)
{
    std::string str;
    std::string cinstr;
    std::getline(std::cin, cinstr);
    for (auto it : cinstr)
    {
        if (it == ' ')
        {
	    if(str.size()>0)
	    { 
            commend.push_back(move(str));
	    }
	}
        else
        {
            str.push_back(it);
        }
    }
    commend.push_back(move(str));
}

void MyFork(std::vector<std::string>& commend)
{
	char* argv[ARGV_SIZE] = { NULL };
	int i=0;
	for(i=0;i<commend.size();i++)
	{
		argv[i] = (char*)commend[i].c_str();
	}
	argv[i]=NULL;

	pid_t childid = fork();
	if(childid==0)
	{
        	execvp(argv[0], argv);
		exit(1);
    	}
	int status=0;
      	pid_t rid = waitpid(-1, &status, 0);
	if (rid>0)
	{
		lastcode = WEXITSTATUS(status);
	}
}

void PrintEnv()
{
	for (int i=0;environ[i];++i)
	{
		std::cout<<"==="<<environ[i]<<std::endl;
	}
}	
void PrintMyEnv(std::map<std::string,std::string>& env)
{
	for(auto it : env)
	{
		std::cout << it.first << "====" << it.second << std::endl;
	}
}	
void GetMyEnv(std::map<std::string,std::string>& env)
{
	std::string key;
	std::string value;
	int flag = 0;
	
	for(int i=0;environ[i];++i)
	{
		flag = 0;
		for (int j = 0;environ[i][j];++j)
		{
			if (flag == 0)
			{
				if (environ[i][j] == '=')
				{
					flag = 1;
				}
				else
				{
					key.push_back(environ[i][j]);
				}
			}
			else
			{
				value.push_back(environ[i][j]);
			}
		}
		env[move(key)] = move(value);
	}
}

void  MyChdir(std::string& path,std::map<std::string,std::string>& env)
{
	if(path=="~")
	{
		char* homepath = (char*)env["HOME"].c_str();
		int v = chdir(homepath);
		if (v==0)
                {
                        env["PWD"]=homepath;
                }

	}
	else
	{
		int v = chdir((char*)path.c_str());
		if (v==0)
		{
			env["PWD"]=path;
		}
	}
}
int main()
{
	std::vector<std::string> mycommand;
	std::map<std::string,std::string> myenv;
	GetMyEnv(myenv);
	//PrintMyEnv(myenv);
	while(1)
	{
		//打印命令行格式
		PrintCommandPrompt(myenv);
		
		//获取解析命令
		GetCommand(mycommand); 	
	
		//调用子进程
		for (auto it : mycommand)
		{
		     printf("%s ", it.c_str());
		}
		printf("\n");
		if (mycommand[0]=="cd")
		{
			//cd命令判断
			if(mycommand.size()==2)
			{
				MyChdir(mycommand[1],myenv);
			}
		}
		else if (mycommand[0]=="echo")
		{
			if (mycommand.size()==2)
			{
				//echo命令
				if (mycommand[1]=="$?")
				{
					std::cout<< lastcode <<std::endl;
					lastcode = 0; 
				}
				else
				{
					std::cout<<mycommand[1]<<"==="<<myenv[mycommand[1]] <<std::endl;
				}
			}
		}
		else if(mycommand[0]=="env" && mycommand.size()==1)
		{
			PrintMyEnv(myenv);
		}
		else
		{
			//其他命令
			MyFork(mycommand);
		}
	 	//waitpid(-1, NULL, 0);	
 		//exit退出

		mycommand.clear();
	}
	
	return 0;
}

